//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;

namespace OpenLS.Spreadsheet.Collections
{
    class SparseArrayDictionary<TValue>: IFrugalDictionary<TValue> where TValue: class
    {
        const int capacity = 16;
        #region IFrugalDictionary<TValue> Members

        int IFrugalDictionary<TValue>.Count
        {
            get { return storage.Count; }
        }

        bool IFrugalDictionary<TValue>.Remove(int key)
        {
#if DEBUG
            Contract.Requires(IsValid);
            Contract.Ensures(IsValid);
            Contract.Ensures(!this.ContainsKey(key));
#endif
            for (int i = 0; i < storage.Count; i++)
            {
                if (storage[i].Key == key)
                {
                    storage.RemoveAt(i);
                    return true;
                }
            }
            return false;
        }
        public bool ContainsKey(int key)
        {
            TValue value;
            IFrugalDictionary<TValue> dic = this;
            return dic.TryGetValue(key, out value);
        }


        public IEnumerator<int> GetEnumerator()
        {
            foreach (KeyValuePair<int, TValue> pair in storage)
                yield return pair.Key;
        }

        bool IFrugalDictionary<TValue>.TryGetValue(int key, out TValue value)
        {
            foreach (KeyValuePair<int, TValue> pair in storage)
            {
                if (pair.Key == key)
                {
                    value = pair.Value;
                    return true;
                }
            }
            value = default(TValue);
            return false;
        }
#if DEBUG
        bool IsValid
        {
            get
            {
                return this.storage.Count == Enumerable.Count(Enumerable.Distinct(Enumerable.Select(storage, p => p.Key)));
            }
        }
#endif


        IFrugalDictionary<TValue> IFrugalDictionary<TValue>.TryAddValue(int key, TValue value)
        {
#if DEBUG
            Contract.Requires(IsValid);
            Contract.Requires(!ContainsKey(key));
            Contract.Ensures(IsValid);
#endif
            if (storage.Count > capacity)
            {
                int min = int.MaxValue;
                int max = int.MinValue;
                foreach (int k in this)
                {
                    min = Math.Min(min, k);
                    max = Math.Max(max, k);
                }
                int minCluster = min / FixedArrayDictionary<TValue>.Capacity;
                int maxCluster = max / FixedArrayDictionary<TValue>.Capacity;
                if (minCluster != maxCluster)
                    return new ClusteredDictionary<TValue>();
                return new FixedArrayDictionary<TValue>(minCluster * FixedArrayDictionary<TValue>.Capacity);
            }
            storage.Add(new KeyValuePair<int, TValue>(key, value));
            return null;
        }
        List<KeyValuePair<int, TValue>> storage = new List<KeyValuePair<int, TValue>>();

        #endregion
    }
}
